<script setup lang="tsx">
import { computed, getCurrentInstance, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import type { NumberAnimationInst } from 'naive-ui'
import dayjs from 'dayjs'
import { Activity } from '@vicons/tabler'
import { DocumentOnePage24Regular } from '@vicons/fluent'
import { useWebSocket } from '@vueuse/core'
import { MovingNumbers } from 'moving-numbers-vue3'
import moment from 'moment'
import {
  expectMessageAdd,
  getSimulation,
  getTelemetryLogList,
  sendSimulation,
  telemetryDataCurrent,
  telemetryDataDel,
  telemetryDataPub
} from '@/service/api'
import { localStg } from '@/utils/storage'
import { deviceDetail } from '@/service/api/device'
import { $t } from '@/locales'
import { getWebsocketServerUrl, isJSON } from '@/utils/common/tool'
import { deviceCustomControlList } from '@/service/api/system-data'
import HistoryData from './modules/history-data.vue'
import TimeSeriesData from './modules/time-series-data.vue'
import { useLoading } from '~/packages/hooks'
const props = defineProps<{
  id: string
  deviceTemplateId: string
}>()

let wsUrl = getWebsocketServerUrl()
wsUrl += '/telemetry/datas/current/ws'
const showDialog = ref(false)
const showLogDialog = ref(false)
const showHistory = ref(false)
const telemetryId = ref()
const telemetryKey = ref()
const telemetryName = ref()
const telemetryUnit = ref()
const modelType = ref<string>('')

const formValue = ref('')
const form = reactive({
  expected: false,
  time: null
})
const operationType = ref('')
const sendResult = ref('')
const tableData = ref([])

const telemetryData = ref<DeviceManagement.telemetryData[]>([])
const initTelemetryData = ref<any>()
const numberAnimationInstRef = ref<NumberAnimationInst[] | []>([])
const nowTime = ref<any>()
const { loading, startLoading, endLoading } = useLoading()
const total = ref(0)
const showLog = ref(false)
const device_order = ref('')
const operationOptions = [
  { label: $t('custom.device_details.whole'), value: '' },
  { label: $t('custom.device_details.manualOperation'), value: '1' },
  { label: $t('custom.device_details.triggerOperation'), value: '2' }
  // 其他操作类型选项...
]
const resultOptions = [
  { label: $t('custom.device_details.whole'), value: '' },
  { label: $t('custom.devicePage.success'), value: '1' },
  { label: $t('custom.devicePage.fail'), value: '2' }
  // 其他发送结果选项...
]
const cardHeight = ref(160) // 卡片的高度
const cardMargin = ref(15) // 卡片的间距
const log_page = ref(1)
const showError = ref(false)
const erroMessage = ref('')

const token = localStg.get('token')

const { status, send, close } = useWebSocket(wsUrl, {
  heartbeat: {
    message: 'ping',
    interval: 8000,
    pongTimeout: 3000
  },
  // eslint-disable-next-line
  onMessage(ws: WebSocket, event: MessageEvent) {
    if (event.data && event.data !== 'pong') {
      const info = JSON.parse(event.data)
      const currTelemetryKey = telemetryData.value
        .map(item => {
          return item.key === 'systime' ? false : item.key
        })
        .filter(item => Boolean(item))
      const newData = telemetryData.value.map(item => {
        return {
          ...item,
          value:
            info[item.key] === null || info[item.key] === undefined || info[item.key] === ''
              ? item.value
              : info[item.key],
          ts: info[item.key] && info.systime ? info.systime : item.ts || ''
        }
      })
      const newTelemetry: any[] = []
      for (const key in info) {
        if (key !== 'systime' && !currTelemetryKey.includes(key)) {
          const { key: _originKey, label: _label, ...rest } = initTelemetryData.value
          newTelemetry.push({
            ...rest,
            key,
            value: info[key],
            ts: info.systime,
            unit: ''
          })
        }
      }
      telemetryData.value = [...newData, ...newTelemetry]
    }
  }
})

const columns = [
  {
    title: $t('custom.device_details.command'),
    minWidth: '140px',
    key: 'data'
  },
  {
    title: $t('custom.device_details.operationType'),
    key: 'operation_type',
    minWidth: '140px',
    render: row => (row.operation_type === '1' ? $t('custom.device_details.manualOperation') : $t('card.triggerAction'))
  },
  {
    title: $t('custom.device_details.operationUsers'),
    minWidth: '140px',
    key: 'username',
    render: row => (row.operation_type === '1' ? row.username : $t('generate.system'))
  },
  {
    title: $t('custom.device_details.operationTime'),
    key: 'created_at',
    minWidth: '140px',
    render: row => dayjs(row.created_at).format('YYYY-MM-DD HH:mm:ss')
  },
  {
    title: $t('custom.device_details.sendResults'),
    minWidth: '140px',
    key: 'status',
    render: row => (row.status === '1' ? $t('custom.devicePage.success') : $t('custom.devicePage.fail'))
  }
]
const requestSimulationList = async () => {
  const { data, error } = await getSimulation({
    device_id: props.id
  })
  if (!error) {
    device_order.value = data
  }
}

const openDialog = () => {
  showDialog.value = true
  formValue.value = ''
  form.expected = false
  form.time = null
}
const openUpLog = () => {
  showError.value = false
  showLogDialog.value = true
  requestSimulationList()
}

const sendSimulationList = async () => {
  if (!device_order.value) {
    window.$message?.error($t('custom.device_details.sendInputData'))
    return
  }
  const { error } = await sendSimulation({
    command: device_order.value
  })
  if (!error) {
    showLogDialog.value = false
    showError.value = false
  } else {
    showError.value = true
    erroMessage.value = error?.response?.data?.message
  }
}
const fetchData = async () => {
  startLoading()
  const { data, error } = await getTelemetryLogList({
    page: log_page.value,
    page_size: 5,
    device_id: props.id,
    operation_type: operationType.value,
    status: sendResult.value
  })
  if (!error) {
    tableData.value = data?.value || data.list
    total.value = Math.ceil(data.count / 5)
    endLoading()
  }
}

const fetchTelemetry = async () => {
  const { data, error } = await telemetryDataCurrent(props.id)
  if (!error && data) {
    telemetryData.value = data
    initTelemetryData.value = data[0] || {} // 存储一份模板
    initTelemetryData.value.device_id = props.id
    const dataw = {
      // eslint-disable-next-line no-constant-binary-expression
      device_id: props.id,
      token
    }

    send(JSON.stringify(dataw))
  }
}
const setItemRef = el => {
  if (el) {
    const index = el.$attrs['data-index']
    numberAnimationInstRef.value[index] = el
  }
}
const getDeviceDetail = async () => {
  const { data, error } = await deviceDetail(props.id)
  if (!error) {
    if (data.device_config !== undefined) {
      if (data.device_config.protocol_type === 'MQTT') {
        showLog.value = true
      } else {
        showLog.value = false
      }
    } else {
      showLog.value = true
    }
  }
}
getDeviceDetail()

const options = ref([
  {
    label: $t('custom.device_details.deleteAttribute'),
    key: '1'
  }
])

const delparam: any = ref({})

const handleDeleteTable = async () => {
  const { error }: any = await telemetryDataDel(delparam.value)

  if (!error) {
    fetchTelemetry()
  }
}

const handleSelect = (key, item) => {
  if (String(key) === '1') {
    delparam.value = {
      key: item.key,
      device_id: props.id
    }
    handleDeleteTable()
  }
}
const copy = event => {
  const input = event.target
  input.select()
  document.execCommand('copy')
  window.$message?.success($t('theme.configOperation.copySuccess'))
}
const handlePositiveClick = async () => {
  if (isJSON(formValue.value)) {
    let res: any = {}
    if (form.expected) {
      // 新增期望消息
      const expiry = new Date().getTime() + (form.time ? form.time * 60 * 60 * 1000 : 0)
      res = await expectMessageAdd({
        device_id: props.id,
        payload: formValue.value,
        send_type: 'telemetry',
        expiry: moment(expiry).format('YYYY-MM-DDTHH:mm:ssZ')
      })
    } else {
      // 发送属性的逻辑...
      res = await telemetryDataPub({
        device_id: props.id,
        value: formValue.value
      })
    }
    if (res && !res.error) {
      showDialog.value = false
      fetchData()
      fetchTelemetry()
    }
  }
}

const onTapTableTools = (i: any) => {
  if (typeof i.value === 'number') {
    modelType.value = $t('custom.device_details.sequential')
    telemetryKey.value = i.key
    telemetryName.value = i.label
    telemetryId.value = i.device_id
    telemetryUnit.value = i.unit
    showHistory.value = true
  }
}

const isColor = (i: any) => {
  if (typeof i.value !== 'number') {
    return '#cccccc'
  }
  return ''
}

const controlList = ref<any[]>([])
const getControlList = () => {
  if (props.deviceTemplateId) {
    const queryjson = {
      device_template_id: props.deviceTemplateId,
      page: 1,
      page_size: 100,
      enable_status: 'enable'
    }
    deviceCustomControlList(queryjson).then(({ data }) => {
      controlList.value = data.list || []
    })
  }
}

watch(
  () => props.deviceTemplateId,
  val => {
    if (!val) return
    getControlList()
  }
)
onMounted(() => {
  fetchData()
  fetchTelemetry()
  getControlList()
})

onUnmounted(() => {
  if (status.value === 'OPEN') {
    close()
  }
})

const onControlChange = async (row: any) => {
  await telemetryDataPub({
    device_id: props.id,
    value: row.content
  })
  fetchData()
}

const getPlatform = computed(() => {
  const { proxy }: any = getCurrentInstance()
  return proxy.getPlatform()
})

const validationJson = computed(() => {
  if (formValue.value && !isJSON(formValue.value)) {
    return 'error'
  }
  return undefined
})
const inputFeedback = computed(() => {
  if (formValue.value && !isJSON(formValue.value)) {
    return $t('generate.inputRightJson')
  }
  return ''
})
</script>

<template>
  <n-card class="w-full">
    <!-- 第一行 -->
    <NFlex justify="space-between">
      <n-button type="primary" class="mb-4" @click="openDialog">{{ $t('generate.issue-control') }}</n-button>

      <n-button v-if="showLog" type="primary" class="mb-4" @click="openUpLog">
        {{ $t('generate.simulate-report-data') }}
      </n-button>
    </NFlex>

    <!-- 自定义控制 -->
    <NGrid x-gap="20" y-gap="20" cols="1 s:2 m:3 l:4" responsive="screen" class="mb-4">
      <NGridItem v-for="item in controlList" :key="item.id">
        <NCard hoverable>
          <div class="title cursor-pointer ellipsis-text text-16px font-600" @click="onControlChange(item)">
            {{ item.name }}
          </div>
        </NCard>
      </NGridItem>
    </NGrid>

    <!-- 第二行 -->
    <n-card class="mb-4">
      <n-grid :x-gap="cardMargin" :y-gap="cardMargin" cols="1 600:2 900:3 1200:4">
        <n-gi v-for="(i, index) in telemetryData" :key="i.tenant_id">
          <n-card header-class="border-b h-36px" hoverable :style="{ height: cardHeight + 'px' }">
            <div class="card-body">
              <n-tooltip v-if="isColor(i)" trigger="hover" placement="top">
                <template #trigger>
                  <span class="value-display-ellipsis" style="font-size: 24px">
                    {{ i.value }}
                  </span>
                </template>
                <div style="max-width: 300px; word-break: break-all">{{ i.value }}</div>
              </n-tooltip>
              <MovingNumbers
                v-else
                :ref="setItemRef"
                :data-index="index"
                :m-num="i.value"
                :quantile-show="true"
              ></MovingNumbers>
              <span v-if="i.unit">{{ i.unit }}</span>
            </div>
            <template #header>
              <div class="line1" :title="i.key">
                <template v-if="i.label">
                  <span v-if="i.label">{{ i.label }}</span>
                  <span>({{ i.key }})</span>
                </template>
                <template v-else>
                  <span>{{ i.key }}</span>
                </template>
              </div>
            </template>
            <template #footer>
              <div class="flex justify-end">
                {{ i.ts ? dayjs(i.ts).format('YYYY-MM-DD HH:mm:ss') : nowTime }}
              </div>
            </template>
            <template #header-extra>
              <div class="h-24px w-120px flex items-center justify-end">
                <NIcon
                  size="24"
                  @click="
                    () => {
                      modelType = $t('custom.device_details.history')
                      telemetryKey = i.key
                      telemetryName = i.label
                      telemetryUnit = i.unit
                      telemetryId = i.device_id
                      showHistory = true
                    }
                  "
                >
                  <DocumentOnePage24Regular />
                </NIcon>
                <NDivider vertical />
                <NIcon size="24" :color="isColor(i)" @click="onTapTableTools(i)">
                  <Activity />
                </NIcon>
                <NDivider vertical />
                <n-dropdown trigger="click" :options="options" @select="handleSelect($event, i)">
                  <svg
                    style="width: 20px"
                    xmlns="http://www.w3.org/2000/svg"
                    xmlns:xlink="http://www.w3.org/1999/xlink"
                    viewBox="0 0 16 16"
                  >
                    <g fill="none">
                      <path
                        d="M5 8a1 1 0 1 1-2 0a1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0a1 1 0 0 1 2 0zm3 1a1 1 0 1 0 0-2a1 1 0 0 0 0 2z"
                        fill="currentColor"
                      ></path>
                    </g>
                  </svg>
                </n-dropdown>
              </div>
            </template>
          </n-card>
        </n-gi>
      </n-grid>
    </n-card>

    <!-- 第三行 -->
    <n-space>
      <n-select
        v-model:value="operationType"
        :options="operationOptions"
        style="width: 200px"
        @update:value="fetchData"
      />
      <n-select v-model:value="sendResult" :options="resultOptions" style="width: 200px" @update:value="fetchData" />
    </n-space>

    <!-- 第四行 -->

    <n-data-table :loading="loading" class="mt-4" :columns="columns" :data="tableData" :pagination="false" />
    <div class="mt-4 w-full flex justify-end">
      <n-pagination
        :page-count="total"
        :page-size="5"
        @update:page="
          page => {
            log_page = page
            fetchData()
          }
        "
      />
    </div>
    <n-modal v-model:show="showLogDialog" :title="$t('generate.report-data')" :class="getPlatform ? 'w-90%' : 'w-40%'">
      <n-card>
        <n-form>
          <div class="m-b-20px" :class="getPlatform ? ' flex-col ' : ' flex'">
            <span class="flex-1">{{ $t('generate.mqtt') }}</span>
            <span class="flex-1">{{ $t('generate.copy-commands-to-local') }}</span>
          </div>
          <div class="flex items-center gap-15px">
            <n-input v-model:value="device_order" type="textarea" class="flex-1" @click="copy" />

            <n-button type="primary" @click="sendSimulationList">
              {{ $t('generate.send') }}
            </n-button>
          </div>
          <div v-if="showError" class="w-100% flex" style="border: 2px solid #eee; border-radius: 5px">
            <SvgIcon
              local-icon="AlertFilled"
              style="margin-left: 5px; color: red; margin-right: 5px; margin-top: 5px; margin-bottom: 5px"
              class="text-20px text-primary"
            />
            <span
              style="
                display: inline-block;
                margin-top: 5px;
                margin-bottom: 5px;
                width: 300px;
                wite-space: nowrap;
                overflow: hidden;
                overflow: hidden;
                text-overflow: ellipsis;
              "
            >
              {{ erroMessage }}99999
            </span>
          </div>
        </n-form>
      </n-card>
    </n-modal>
    <n-modal v-model:show="showDialog" :class="getPlatform ? 'w-90%' : 'w-40%'">
      <n-card :title="$t('generate.distributeControlToDevice')">
        <n-form label-placement="left">
          <div class="flex">
            <n-form-item>
              <template #label>
                <div class="flex-ai-c flex">
                  {{ $t('generate.expectedMessage') }}
                  <n-popover trigger="hover">
                    <template #trigger>
                      <svg
                        style="width: 20px"
                        xmlns="http://www.w3.org/2000/svg"
                        xmlns:xlink="http://www.w3.org/1999/xlink"
                        viewBox="0 0 20 20"
                      >
                        <g fill="none">
                          <path
                            d="M10 2a8 8 0 1 1-3.613 15.14l-.121-.065l-3.645.91a.5.5 0 0 1-.62-.441v-.082l.014-.083l.91-3.644l-.063-.12a7.95 7.95 0 0 1-.83-2.887l-.025-.382L2 10a8 8 0 0 1 8-8zm0 1a7 7 0 0 0-6.106 10.425a.5.5 0 0 1 .063.272l-.014.094l-.756 3.021l3.024-.754a.502.502 0 0 1 .188-.01l.091.021l.087.039A7 7 0 1 0 10 3zm0 2.5a.5.5 0 0 1 .5.5v5.5a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm0 9a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5z"
                            fill="currentColor"
                          ></path>
                        </g>
                      </svg>
                    </template>
                    <span>{{ $t('generate.expectedMessageTip') }}</span>
                  </n-popover>
                </div>
              </template>

              <n-switch v-model:value="form.expected" />
            </n-form-item>
            <n-form-item v-if="form.expected" :label="$t('generate.expirationTime')" class="ml-20px">
              <div class="flex-ai-c flex">
                <n-input-number v-model:value="form.time" :show-button="false" class="w-80px" />
                <div class="fs-0">{{ $t('generate.hour') }}</div>
              </div>
            </n-form-item>
          </div>
          <n-form-item label="" :validation-status="validationJson" :feedback="inputFeedback">
            <n-input v-model:value="formValue" type="textarea" />
          </n-form-item>
          <n-space align="end">
            <n-button @click="showDialog = false">{{ $t('generate.cancel') }}</n-button>

            <n-popconfirm @positive-click="handlePositiveClick">
              <template #trigger>
                <n-button type="primary" :disabled="!formValue || validationJson === 'error'">
                  {{ $t('generate.send') }}
                </n-button>
              </template>
              确定发送指令吗
            </n-popconfirm>
          </n-space>
        </n-form>
      </n-card>
    </n-modal>
    <n-modal v-model:show="showHistory" :title="$t('generate.telemetry-history-data')">
      <NCard style="width: 80%">
        <HistoryData
          v-if="modelType === $t('custom.device_details.history')"
          :device-id="telemetryId"
          :the-key="telemetryKey"
          :the-name="telemetryName"
          :the-unit="telemetryUnit"
        />
        <TimeSeriesData
          v-if="modelType === $t('custom.device_details.sequential')"
          :device-id="telemetryId"
          :the-key="telemetryKey"
          :the-name="telemetryName"
          :the-unit="telemetryUnit"
        />
      </NCard>
    </n-modal>
  </n-card>
</template>

<style lang="scss" oped>
.line1 {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;

  span {
    &:nth-child(2) {
      color: #ccc;
      padding-left: 5px;
    }
  }
}

.card-body {
  padding: 10px 0 10px;
  display: flex;
  align-items: end;
  gap: 4px;

  span {
    &:first-child {
      font-size: 32px;
      line-height: 1;
    }
  }
}
.ml-20px {
  margin-left: 20px;
}
.flex-ai-c {
  align-items: center;
}
.w-80px {
  width: 80px;
}
.fs-0 {
  flex-shrink: 0;
}
.chart-table-dialog {
  width: 80%;
  max-width: 1000px;
}

.value-display-ellipsis {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-all; /* Or 'break-word' if preferred */
}
</style>
